home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / pcr / pcr4_4.lha / DIST / gc / GCallochblk.c < prev    next >
C/C++ Source or Header  |  1992-02-25  |  20KB  |  636 lines

  1. /* begincopyright
  2.   Copyright (c) 1988,1990 Xerox Corporation. All rights reserved.
  3.   Use and copying of this software and preparation of derivative works based
  4.   upon this software are permitted. Any distribution of this software or
  5.   derivative works must comply with all applicable United States export
  6.   control laws. This software is made available AS IS, and Xerox Corporation
  7.   makes no warranty about the software, its performance or its conformity to
  8.   any specification. Any person obtaining a copy of this software is requested
  9.   to send their name and post office or electronic mail address to:
  10.     PCR Coordinator
  11.     Xerox PARC
  12.     3333 Coyote Hill Rd.
  13.     Palo Alto, CA 94304
  14.     
  15.   Parts of this software were derived from code bearing the copyright notice:
  16.   
  17.   Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  18.   This material may be freely distributed, provided this notice is retained.
  19.   This material is provided as is, with no warranty expressed or implied.
  20.   Use at your own risk.
  21.   
  22.   endcopyright */
  23. /*
  24.  *  Boehm, October 11, 1991 10:31:22 am PDT
  25.  */
  26.  
  27. #define DEBUG
  28.  
  29. #define VERBOSE
  30. #undef VERBOSE
  31. #include "xr/GCPrivate.h"
  32. #include "xr/Threads.h"
  33. #include "xr/ThreadsMsg.h"
  34. #define I_HOLD_ML(ml) (((XR_ML)(ml))->ml_holder == XR_currThread)
  35. #ifdef BLACK_LIST
  36. #  define MAX_BLACK_LIST_ALLOC (2*HBLKSIZE)
  37.         /* largest block we will allocate starting on a black   */
  38.         /* listed block.  Must be >= HBLKSIZE.            */
  39. #endif
  40.  
  41.   
  42. /**/
  43. /* allocate/free routines for heap blocks
  44. /* Note that everything called from outside the garbage collector
  45. /* should be prepared to abort at any point as the result of a signal.
  46. /* GC_expand_hp is also here.
  47. /**/
  48.  
  49. /*
  50.  * Free heap blocks are kept on a list sorted by address.
  51.  * The hb_hdr.hbh_sz field of a free heap block contains the length
  52.  * (in bytes) of the entire block.
  53.  * Neighbors are coalesced.
  54.  */
  55.  
  56. struct hblk *GC_savhbp = (struct hblk *)0;  /* heap block preceding next */
  57.                         /* block to be examined by   */
  58.                         /* allochblk.                */
  59.                         /* Protected by GC_allocate_ml */
  60. int GC_small_blocks = 0;    /* Number of free blocks of size 1 on the */
  61.                 /* heap block free list.          */
  62. /*
  63.  * Return TRUE if there is a heap block sufficient for object size sz,
  64.  * FALSE otherwise.  Advance GC_savhbp to point to the block prior to the
  65.  * first such block.
  66.  * Should hold GC_allocate_ml, since GC_savhbp is updated.
  67.  */
  68. bool GC_sufficient_hb(sz)
  69. int sz;
  70. {
  71.     register struct hblk *hbp, *h;
  72.     struct hblk *prevhbp;
  73.     int size_needed, size_avail;
  74.     register char * GC_heapstart_reg = GC_heapstart;
  75. #   define GC_heapstart GC_heapstart_reg
  76.     int first_time = 1;
  77.  
  78.     if (!I_HOLD_ML(&GC_allocate_ml)) {
  79.         GC_abort("GC_sufficient_hb 0");
  80.     }
  81.     size_needed = WORDS_TO_BYTES(abs(sz));
  82.     size_needed = (size_needed+HDR_BYTES+HBLKSIZE-1) & ~HBLKMASK;
  83. #   ifdef VERBOSE
  84.     GC_vprintf("sufficient_hb: sz = %d, size_needed = 0x%X\n",
  85.               sz, size_needed);
  86. #   endif
  87.     /* search for a big enough block in free list */
  88.     hbp = GC_savhbp;
  89.     for(;;) {
  90.         prevhbp = hbp;
  91.         hbp = ((prevhbp == (struct hblk *)0)
  92.             ? GC_hblkfreelist
  93.             : hb_next(prevhbp));
  94.  
  95.         if( prevhbp == GC_savhbp && !first_time) {
  96.         /* no sufficiently big blocks on free list */
  97.         return(FALSE);
  98.         }
  99.         first_time = 0;
  100.         if( hbp == (struct hblk *)0 ) continue;
  101.         size_avail = hb_sz(hbp);
  102. #        ifdef DEBUG
  103.         if (GC_small_blocks == 0 && size_avail == HBLKSIZE) {
  104.             GC_abort("GC_sufficient_hb: GC_small_blocks is wrong\n");
  105.         }
  106. #        endif DEBUG
  107. #        ifdef BLACK_LIST
  108.           if( size_avail >= size_needed && sz < 0
  109.               && size_needed <= MAX_BLACK_LIST_ALLOC) {
  110.           GC_savhbp = prevhbp;
  111.           return(TRUE);
  112.           }
  113.           h = hbp;
  114.           while (size_avail >= size_needed && is_black_listed(h)) {
  115.             h++; size_avail -= HBLKSIZE;
  116.           }
  117. #        endif
  118.         if( size_avail >= size_needed) {
  119.         GC_savhbp = prevhbp;
  120.         return(TRUE);
  121.         }
  122.     }
  123. #   undef GC_heapstart;
  124. }
  125.  
  126. /*
  127.  * Allocate (and return pointer to) a heap block
  128.  *   for objects of size |sz|.
  129.  *
  130.  * NOTE: Caller is responsible for adding it to global hblklist
  131.  *       and for building an object freelist in it.
  132.  *       We allocate the header, no matter where it resides.
  133.  *
  134.  * The new block is guaranteed to be cleared if sz > 0.
  135.  * Returns (struct hblk *)0 if the allocation request fails.
  136.  */
  137. struct hblk *
  138. GC_allochblk(sz)
  139. long sz;
  140. {
  141.     register struct hblk *thishbp;
  142.     register struct hblk *hbp;
  143.     struct hblk *prevhbp;
  144.     long size_needed,            /* number of bytes in requested objects */
  145.          uninit,                 /* => Found uninitialized block         */
  146.          size_avail;
  147.     register char * GC_heapstart_reg = GC_heapstart;
  148. #   define GC_heapstart GC_heapstart_reg
  149.     int first_time = 1;
  150.     
  151.     
  152.     if (!I_HOLD_ML(&GC_allocate_ml)) {
  153.         GC_abort("GC_allochblk 0");
  154.     }
  155.     size_needed = WORDS_TO_BYTES(sz>0? sz : -sz);
  156.     size_needed = (size_needed+HDR_BYTES+HBLKSIZE-1) & ~HBLKMASK;
  157. #   ifdef VERBOSE
  158.     GC_vprintf(
  159.         "(allochblk) sz = %x, size_needed = 0x%X\n", sz, size_needed);
  160. #   endif
  161.  
  162.     /* search for a big enough block in free list */
  163.     hbp = GC_savhbp;
  164.     for(;;) {
  165.  
  166.         prevhbp = hbp;
  167.         hbp = ((prevhbp == (struct hblk *)0)
  168.                     ? GC_hblkfreelist
  169.             : hb_next(prevhbp));
  170.  
  171.         if( prevhbp == GC_savhbp && !first_time) {
  172.         /* no sufficiently big blocks on free list, */
  173.         /* expand the heap and try again.           */
  174.                   int blocks_to_get =
  175.                       divHBLKSZ(size_needed + HBLKSIZE
  176.                           + GC_composite_in_use/GC_free_mem_ratio);
  177.                   
  178.                   if (blocks_to_get < MIN_HINCR) {
  179.                       blocks_to_get = MIN_HINCR;
  180.                   }
  181.                   if (!GC_expand_hp(blocks_to_get, FALSE)) {
  182.                       GC_iprintf(
  183.                           "Out of memory - attempting emergency collection\n");
  184.               /* This the right thing? */
  185.                       GC_demand_full_and_wait();
  186.                       GC_reclaim_empty_pages();
  187.                       if (GC_sufficient_hb(sz)) {
  188.                           return(GC_allochblk(sz));
  189.                       } else {
  190.                           return((struct hblk *)0);
  191.                       }
  192.                   }
  193. #                 ifdef PRINTSTATS
  194.             GC_printf("Increased heap size for size %d request\n",
  195.                       sz);
  196. #                 endif
  197.           return(GC_allochblk(sz));
  198.         }
  199.  
  200.         first_time = 0;
  201.  
  202.         if( hbp == (struct hblk *)0 ) continue;
  203.  
  204.         size_avail = hb_sz(hbp);
  205. #        ifdef BLACK_LIST
  206.           if (sz > 0 || size_needed > MAX_BLACK_LIST_ALLOC) {
  207.               while(is_black_listed(hbp) && size_avail >= size_needed) {
  208.                 size_avail -= HBLKSIZE;
  209.                 if (size_avail >= size_needed) {
  210.                    /* allocate the first block, and drop it.  It'll be */
  211.                    /* reconsidered after the next collection.        */
  212.                   thishbp = hbp;
  213.                   hbp = thishbp + 1;
  214.                   if (thishbp == GC_savhbp) {
  215.                     /* Advance GC_savhbp so that termination test is */
  216.                     /* still meaningful.                   */
  217.                       GC_savhbp = hbp;
  218.                   }
  219. #                     ifdef SEPARATE_HEADERS
  220.               GC_get_header(hbp);
  221. #                     endif
  222.               hb_uninit(hbp) = hb_uninit(thishbp);
  223.               hb_next(hbp) = hb_next(thishbp);
  224.               hb_sz(hbp) = size_avail;
  225.               if (size_avail == HBLKSIZE) {
  226.               GC_small_blocks++;
  227.               }
  228.               if( prevhbp == (struct hblk *)0 ) {
  229.             GC_hblkfreelist = hbp;
  230.               } else {
  231.             hb_next(prevhbp) = hbp;
  232.               }
  233.               hb_sz(thishbp) = -BYTES_TO_WORDS(HBLKSIZE - HDR_BYTES);
  234.               {
  235.                 register word *p = (word *)(&(hb_marks(thishbp)[0]));
  236.                 register word * plim =
  237.                     (word *)(&(hb_marks(thishbp)[MARK_BITS_SZ]));
  238.                 while (p < plim) {
  239.               *p++ = 0;
  240.                 }
  241.               }
  242.                   hb_busy(thishbp) = 0;
  243.               hb_tenured(thishbp) = 0;
  244.               GC_add_hblklist(thishbp);
  245.                 } /* else dont bother ... */
  246.               }
  247.           }
  248. #        endif /* BLACK_LIST */
  249.  
  250.         if( size_avail >= size_needed) {
  251.         /* found a big enough block       */
  252.         /* let thishbp --> the block      */
  253.         /* set prevhbp, hbp to bracket it */
  254.             thishbp = hbp;
  255.             if( size_avail == size_needed ) {
  256.                 if (size_needed == HBLKSIZE) {
  257.                     GC_small_blocks--;
  258.                 }
  259.             hbp = hb_next(hbp);
  260.             uninit = hb_uninit(thishbp);
  261.             } else if (size_needed == HBLKSIZE
  262. #                   ifdef BLACK_LIST
  263.                  && sz < 0
  264. #                   endif
  265.                        && GC_small_blocks >= 1) {
  266.                 continue;
  267.             } else {
  268.                 register unsigned long new_sz;
  269.             uninit = hb_uninit(thishbp);
  270.             hbp = (struct hblk *)
  271.                 (((unsigned long)thishbp) + size_needed);
  272. #                       ifdef SEPARATE_HEADERS
  273.                 GC_get_header(hbp);
  274. #                       endif
  275.             hb_uninit(hbp) = uninit;
  276.             hb_next(hbp) = hb_next(thishbp);
  277.             new_sz = size_avail - size_needed;
  278.             hb_sz(hbp) = new_sz;
  279.             if (new_sz == HBLKSIZE) {
  280.                 GC_small_blocks++;
  281.             }
  282.             }
  283.         /* remove *thishbp from hblk freelist */
  284.             if( prevhbp == (struct hblk *)0 ) {
  285.             GC_hblkfreelist = hbp;
  286.             } else {
  287.             hb_next(prevhbp) = hbp;
  288.             }
  289.         /* save current list search position */
  290.         /* Don't look at a block we just split again, since */
  291.         /* that would result in huge chunks getting         */
  292.         /* completely disassembled.                */
  293.             GC_savhbp = hbp;
  294.         break;
  295.         }
  296.     }
  297.  
  298.     /* set size field of *thishbp correctly */
  299.     hb_sz(thishbp) = sz;
  300.  
  301.     /* Clear block if necessary */
  302.     if (uninit && sz > 0) {
  303.         register word * p = &(thishbp -> hb_body[0]);
  304.         register word * plim;
  305.  
  306.         plim = (word *)(((char *)thishbp) + size_needed);
  307.         /* If p is not already 16 byte aligned, then this will  */
  308.         /* cause it to point into the mark bits, which is safe. */
  309.           p = (word*)(((unsigned long)p) & ~(4 * sizeof(word) - 1));
  310.         while (p < plim) {
  311.         p[0] = 0;
  312.         p[1] = 0;
  313.         p[2] = 0;
  314.         p[3] = 0;
  315.         p += 4;
  316.         }
  317.     }
  318.     /* Clear mark bits, hb_busy, and hb_tenured */
  319.     {
  320.         register word *p = (word *)(&(hb_marks(thishbp)[0]));
  321.         register word * plim = (word *)(&(hb_marks(thishbp)[MARK_BITS_SZ]));
  322.         while (p < plim) {
  323.         *p++ = 0;
  324.         }
  325.     }
  326.         hb_busy(thishbp) = 0;
  327.     hb_tenured(thishbp) = 0;
  328.  
  329. #   ifdef VERBOSE
  330.     GC_vprintf("Returning 0x%X\n", thishbp);
  331. #   endif
  332. #   ifdef VISUALIZE
  333.     displayAllocHblk(thishbp, BYTES_TO_WORDS(size_needed));
  334. #   endif
  335.     return( thishbp );
  336. #   undef GC_heapstart;
  337. }
  338.  
  339. /* Clear the header information in a previously allocated heap block p */
  340. /* so that it can be coalesced with an initialized heap block.         */
  341. static GC_clear_header(p)
  342. register struct hblk *p;
  343. {
  344. # ifndef SEPARATE_HEADERS
  345.     hb_sz(p) = 0;
  346.     hb_next(p) = (struct hblk *)0;
  347.     hb_sz_link(p) = (struct hblk *)0;
  348.     hb_uninit(p) = 0;
  349.     hb_tenured(p) = 0;
  350.     hb_busy(p) = 0;
  351.     hb_last_reclaimed(p) = 0;
  352. #   ifdef ALIGN_DOUBLE
  353.      hb_dummy(p) = 0;
  354. #   endif
  355. #   if MARK_BITS_SZ <= 56
  356.     /* Since this block was deallocated, only spurious mark      */
  357.     /* bits corresponding to the header could conceivably be set */
  358.     hb_marks(p)[0] = 0;
  359.     hb_marks(p)[1] = 0;
  360. #   else
  361.     --> fix it
  362. #   endif
  363. # endif
  364. }
  365.  
  366. /*
  367.  * Free a heap block.
  368.  *
  369.  * Assume the block is not currently on hblklist.
  370.  *
  371.  * Coalesce the block with its neighbors if possible.
  372.  
  373.  * All mark words (except possibly the first) are assumed to be cleared.
  374.  * The body is assumed to be cleared unless hb_uninit is nonzero.
  375.  */
  376. void
  377. GC_freehblk(p)
  378. register struct hblk *p;
  379. {
  380. register struct hblk *hbp, *prevhbp;
  381. register long size;
  382. register long prev_sz;
  383. register char * GC_heapstart_reg = GC_heapstart;
  384. # define GC_heapstart GC_heapstart_reg
  385.  
  386.     /* GC_savhbp may become invalid due to coalescing.  Clear it. */
  387.     GC_savhbp = (struct hblk *)0;
  388.  
  389.     size = HB_SIZE(p);
  390.     size = 
  391.     ((WORDS_TO_BYTES(size)+HDR_BYTES+HBLKSIZE-1)
  392.          & (~HBLKMASK));
  393. #   ifdef VISUALIZE
  394.     displayFreeHblk(p, BYTES_TO_WORDS(size));
  395. #   endif
  396.     
  397.     prevhbp = (struct hblk *) 0;
  398.     hbp = GC_hblkfreelist;
  399.  
  400.     while( (hbp != (struct hblk *)0) && (hbp < p) ) {
  401.     prevhbp = hbp;
  402.     hbp = hb_next(hbp);
  403.     }
  404.  
  405.     if (hbp != 0 && (char *)p + size > (char *)hbp) {
  406.         XR_ConsoleMsg("Duplicate large block deallocation\n");
  407.         XR_ConsoleMsg("%? arg = 0x%X -> 0x%X, 0x%X, 0x%X, ",
  408.                   p, ((word *)p)[0], ((word *)p)[1], ((word *)p)[2]);
  409.         XR_ConsoleMsg("0x%X, 0x%X, 0x%X\n",
  410.                   ((word *)p)[3], ((word *)p)[4], ((word *)p)[5]);
  411.         XR_ConsoleMsg("block size = %d (bytes ?)\n", hb_sz(p));
  412.         XR_ConsoleMsg("%? old = 0x%X -> 0x%X, 0x%X, 0x%X, ",
  413.                   hbp, ((word *)hbp)[0], ((word *)hbp)[1],
  414.                   ((word *)hbp)[2]);
  415.         XR_ConsoleMsg("0x%X, 0x%X, 0x%X\n",
  416.                   ((word *)hbp)[3], ((word *)hbp)[4], ((word *)hbp)[5]);
  417.         XR_ConsoleMsg("block size = %d (bytes ?)\n", hb_sz(hbp));
  418.         XR_ConsoleMsg("Calling debugger - Thaw thread to continue\n");
  419.         XR_CallDebugger("Duplicate large block deallocation\n");
  420.         return;
  421.     }
  422.     if (prevhbp != 0 && (char *)prevhbp + hb_sz(prevhbp) > (char *)p) {
  423.         XR_ConsoleMsg("Large block deallocation overlaps free block tail\n");
  424.         XR_ConsoleMsg("%? arg = 0x%X -> 0x%X, 0x%X, 0x%X, ",
  425.                   p, ((word *)p)[0], ((word *)p)[1], ((word *)p)[2]);
  426.         XR_ConsoleMsg("0x%X, 0x%X, 0x%X\n",
  427.                   ((word *)p)[3], ((word *)p)[4], ((word *)p)[5]);
  428.         XR_ConsoleMsg("block size = %d (bytes ?)\n", hb_sz(p));
  429.         XR_ConsoleMsg("%? old = 0x%X -> 0x%X, 0x%X, 0x%X, ",
  430.                   prevhbp, ((word *)prevhbp)[0], ((word *)prevhbp)[1],
  431.                   ((word *)prevhbp)[2]);
  432.         XR_ConsoleMsg("0x%X, 0x%X, 0x%X\n",
  433.                   ((word *)prevhbp)[3], ((word *)prevhbp)[4],
  434.                   ((word *)prevhbp)[5]);
  435.         XR_ConsoleMsg("block size = %d (bytes ?)\n", hb_sz(prevhbp));
  436.         XR_ConsoleMsg("Calling debugger - Thaw thread to continue\n");
  437.         XR_CallDebugger("Duplicate large block deallocation\n");
  438.         return;
  439.     }
  440.     hb_sz(p) = size;
  441.  
  442.     if (size == HBLKSIZE) GC_small_blocks++;
  443.     
  444.     /* Coalesce with successor, if possible */
  445.       if( (((unsigned)p)+size) == ((unsigned)hbp) ) {
  446.         register long next_sz = hb_sz(hbp);
  447.         
  448.     hb_uninit(p) |= hb_uninit(hbp);
  449.     hb_next(p) = hb_next(hbp);
  450.     if (next_sz == HBLKSIZE)  GC_small_blocks--;
  451.     if (size == HBLKSIZE)  GC_small_blocks--;
  452.     size += next_sz;
  453.     hb_sz(p) = size;
  454.     if (!hb_uninit(p)) GC_clear_header(hbp);
  455.       } else {
  456.     hb_next(p) = hbp;
  457.       }
  458.  
  459.     if( prevhbp == (struct hblk *)0 ) {
  460.     GC_hblkfreelist = p;
  461.     } else {
  462.         prev_sz = hb_sz(prevhbp);
  463.         if( (((unsigned)prevhbp) + prev_sz) == ((unsigned)p) ) {
  464.             /* Coalesce with predecessor */
  465.           (hb_uninit(prevhbp)) |= (hb_uninit(p));
  466.           hb_next(prevhbp) = hb_next(p);
  467.           if (prev_sz == HBLKSIZE)  GC_small_blocks--;
  468.           if (size == HBLKSIZE)  GC_small_blocks--;
  469.           hb_sz(prevhbp) = prev_sz + size;
  470.           if (!hb_uninit(prevhbp)) GC_clear_header(p);
  471.         } else {
  472.           hb_next(prevhbp) = p;
  473.     }
  474.     }
  475. # undef GC_heapstart
  476. }
  477.  
  478. /* Add a heap block to hblkmap.  */
  479. void GC_add_hblklist(hbp)
  480. struct hblk * hbp;
  481. {
  482.     long size = HB_SIZE(hbp);
  483.     long index = divHBLKSZ(((long)hbp) - ((long)GC_heapstart));
  484.     long i;
  485.  
  486.     size = (divHBLKSZ(WORDS_TO_BYTES(size)+HDR_BYTES+HBLKSIZE-1));
  487.        /* in units of HBLKSIZE */
  488.     hblkmap[index] = HBLK_VALID;
  489.     for (i = 1; i < size; i++) {
  490.     if (i < 0x7f) {
  491.         hblkmap[index+i] = i;
  492.     } else {
  493.         /* May overflow a char.  Store largest possible value */
  494.         hblkmap[index+i] = 0x7e;
  495.     }
  496.     }
  497. }
  498.  
  499. /* Delete a heap block from hblklist or hblkmap.  */
  500. void GC_del_hblklist(hbp)
  501. struct hblk * hbp;
  502. {
  503.     long size = HB_SIZE(hbp);
  504.     long index = divHBLKSZ(((long)hbp) - ((long)GC_heapstart));
  505.     long i;
  506.  
  507.     size = (divHBLKSZ(WORDS_TO_BYTES(size)+HDR_BYTES+HBLKSIZE-1));
  508.        /* in units of HBLKSIZE */
  509.     if (hblkmap[index] == HBLK_INVALID) {
  510.         /* This implies a duplicate deallocation.  We catch it elsewhere. */
  511.         XR_ConsoleMsg("%? GC_del_hblklist: redundant call\n");
  512.         return;
  513.     }
  514.     for (i = 0; i < size; i++) {
  515.     hblkmap[index+i] = HBLK_INVALID;
  516.     }
  517. }
  518.  
  519.  
  520. typedef void (*GC_expand_call_back_type)(/*XR_Pointer client_data*/);
  521.  
  522. static GC_expand_call_back_type expand_call_back = NIL;
  523. static XR_Pointer expand_call_back_data = NIL;
  524.  
  525. void GC_register_expand_callback(fn, data, Ofn, Odata)
  526. GC_expand_call_back_type fn;
  527. XR_Pointer data;
  528. GC_expand_call_back_type *Ofn;
  529. XR_Pointer *Odata;
  530. {
  531.     XR_MonitorEntry(&GC_allocate_ml);
  532.     if (Ofn != 0) {
  533.         *Ofn = expand_call_back;
  534.     }
  535.     if (Odata != 0) {
  536.         *Odata = expand_call_back_data;
  537.     }
  538.     expand_call_back = fn;
  539.     expand_call_back_data = data;
  540.     XR_MonitorExit(&GC_allocate_ml);
  541. }
  542.  
  543. unsigned long GC_max_heap_size = HEAPLIM - HEAPSTART;
  544.  
  545. /*
  546.  * this explicitly increases the size of the heap.  It is used
  547.  * internally, but may also be invoked directly by the user.
  548.  * The argument is in units of HBLKSIZE.
  549.  * The second argument is TRUE iff this is being called before the threads
  550.  * world has been started.
  551.  * Returns TRUE on success, FALSE on failure.
  552.  * Assumes we hold GC_allocate_ml.
  553.  */
  554. bool GC_expand_hp(n,initial)
  555. unsigned n;
  556. {
  557.     struct hblk * GC_get_sys_mem();
  558.     struct hblk * thishbp;
  559.     char * block_end;
  560. #   ifdef SEPARATE_HEADERS
  561.         long hdr_blks = divHBLKSZ(n * (sizeof (struct hblkhdr)) + HBLKSIZE - 1);
  562.         long size_to_get = (n + hdr_blks) * HBLKSIZE;
  563. #   else
  564.         long size_to_get = n * HBLKSIZE;
  565. #   endif
  566.     long final_size = GC_heapsize + n * HBLKSIZE;
  567.  
  568.     if (final_size > GC_max_heap_size) {
  569.         if (expand_call_back != NIL) {
  570.             (*expand_call_back)(expand_call_back_data);
  571.         }
  572.         if (final_size > GC_max_heap_size) {
  573.             return(FALSE);
  574.         }
  575.     }
  576.     if (initial) {
  577.         thishbp = GC_get_sys_mem_initial(size_to_get);
  578.     } else {
  579.         if (! I_HOLD_ML(&GC_allocate_ml)) {
  580.             XR_ConsoleMsg("%? GC_expand_hp called without GC_allocate_ml\n");
  581.             /* Might want to panic here  ... */
  582.         }
  583.         thishbp = GC_get_sys_mem(size_to_get);
  584.     }
  585.       
  586.     if( thishbp == (struct hblk *)0 ) {
  587.     return(FALSE);
  588.     }
  589.     block_end = (char *) (((unsigned)thishbp) + n * HBLKSIZE);
  590.     if (block_end > GC_heaplim) {
  591.         GC_heaplim = block_end;
  592.         if (((struct hblk *)GC_heaplim)
  593.             - (struct hblk *)GC_heapstart > MAP_SIZE) {
  594.             GC_abort("Exceeded maximum heap size - reconfigure GC!");
  595.         }
  596.     }
  597.  
  598. #   ifdef PRINTSTATS
  599.     XR_LogVMsg "Increasing heap size by %d\n", n*HBLKSIZE);
  600. #   endif
  601. #   ifdef SEPARATE_HEADERS
  602.         GC_use_as_headers(block_end, hdr_blks);
  603.         GC_get_header(thishbp);
  604. #   endif
  605.     hb_sz(thishbp) = BYTES_TO_WORDS(n * HBLKSIZE - HDR_BYTES);
  606.     GC_freehblk(thishbp);
  607.     GC_heapsize = final_size;
  608.     if (!initial && (GC_mode & DIRTY_BITS_REQUIRED)) {
  609.         /* This is always safe, in that this is untouched memory */
  610.         GC_clear_some_dirty_bits(thishbp, GC_heaplim);
  611.     }
  612.     return(TRUE);
  613. }
  614.  
  615.  
  616. /*
  617.  * Returns TRUE if at least N GC pages (i.e. hblocks) are free (no
  618.  * objects at all on them) and 0 otherwise.
  619.  * (Written this way, rather than just to return the number of free
  620.  * pages, to keep working set down by truncating search.)
  621.  */
  622. bool
  623. XR_NfreePagesP(N)
  624. unsigned N;
  625. {
  626.     register struct hblk *hbp;
  627.     register pageCount = 0;
  628.     
  629.     hbp = GC_hblkfreelist;
  630.     while ( (hbp != (struct hblk *)0) && pageCount < N) {
  631.     pageCount += ((WORDS_TO_BYTES(hb_sz(hbp))+HBLKSIZE-1)/HBLKSIZE);
  632.     hbp = hb_next(hbp);
  633.     }
  634.     return pageCount >= N;
  635. }
  636.